﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CopyByteChangedFile
{
    #region event handlers
    //delegates
    internal delegate void FileCopyActionEventHandler(object sender, FileCopyActionEventArgs e);
    internal delegate void FileCopyExceptionEventHandler(object sender, FileCopyExceptionEventArgs e);
    internal delegate void FileCopySuccessfulEventHandler(object sender, FileCopyActionEventArgs e);
    internal delegate void FileCopyNoActionEventHandler(object sender, FileCopyActionEventArgs e);

    //event args classes
    internal class FileCopyExceptionEventArgs : FileCopyActionEventArgs
    {
        public Exception FileCopyException { get; set; }
    }

    internal class FileCopyActionEventArgs : FileCopyEventArgs
    {
    }
    
    // base clases
    internal class FileInformation
    {
        public string FullFileName { get; set; }
        public FileInfo FileInfoObject { get; set; }
    }

    internal abstract class FileCopyEventArgs : EventArgs
    {
        public FileInformation SourceFile { get; set; }
        public FileInformation DestinationFile { get; set; }
    }
    #endregion

    internal class CopyHandler : IDisposable
    {
        #region declarations
        #region event handling
        public event FileCopyActionEventHandler FileCopyAction;
        protected void OnFileCopyAction(
            FileCopyActionEventArgs ea)
        {
            if (FileCopyAction != null)
            {
                FileCopyAction(this, ea);
            }
        }

        public event FileCopyExceptionEventHandler FileCopyException;
        protected void OnFileCopyException(
            FileCopyExceptionEventArgs ea)
        {
            if (FileCopyException != null)
            {
                FileCopyException(this, ea);
            }
        }

        public event FileCopySuccessfulEventHandler FileCopySuccessful;
        protected void OnFileCopySuccessful(
            FileCopyActionEventArgs ea)
        {
            if (FileCopySuccessful != null)
            {
                FileCopySuccessful(this, ea);
            }
        }

        public event FileCopyNoActionEventHandler FileCopyNoAction;
        protected void OnFileCopyNoAction(
            FileCopyActionEventArgs ea)
        {
            if (FileCopyNoAction != null)
            {
                FileCopyNoAction(this, ea);
            }
        }
        #endregion
        #endregion



        #region constructor

        #region dispose pattern (http://www.codeproject.com/Articles/15360/Implementing-IDisposable-and-the-Dispose-Pattern-P)
        // some fields that require cleanup
        private bool disposed = false; // to detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    // clean up managed handles here
                    
                }

                disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
        #endregion
        #endregion



        #region private functions
        /// <summary>
        /// copies the SourceFileName to the Destination directory via the System.IO.File.Copy method
        /// </summary>
        /// <param name="SourceFileName">existence must be checked upfront</param>
        /// <param name="Destination">existence and if its a directory must be checked upfront</param>
        private void _executeFileCopyAction(
            string SourceFileName,
            string Destination)
        {
            //get source file size since source file existance was checked already
            FileInformation fiSource = new FileInformation();
            fiSource.FullFileName = SourceFileName;
            fiSource.FileInfoObject = new FileInfo(fiSource.FullFileName);
            long lngSourceFileSize = fiSource.FileInfoObject.Length;

            //put together destination file name and get its file size
            FileInformation fiDestination = new FileInformation();
            fiDestination.FullFileName = Destination + "\\" + Path.GetFileName(fiSource.FullFileName);
            long lngDestinationFileSize = 0;
            if (File.Exists(fiDestination.FullFileName))
            {
                fiDestination.FileInfoObject = new FileInfo(fiDestination.FullFileName);
                lngDestinationFileSize = fiDestination.FileInfoObject.Length;
            }

            //file size differs no matter if file does not exist or it really is different
            if (lngSourceFileSize != lngDestinationFileSize)
            {
                //copy NOW!
                try
                {
                    //message
                    OnFileCopyAction(new FileCopyActionEventArgs() { SourceFile = fiSource, DestinationFile = fiDestination });

                    //do it
                    File.Copy(fiSource.FullFileName, fiDestination.FullFileName, true);

                    //report 
                    OnFileCopySuccessful(new FileCopyActionEventArgs() { SourceFile = fiSource, DestinationFile = fiDestination });
                }
                catch (Exception ex)
                {
                    OnFileCopyException(new FileCopyExceptionEventArgs() { SourceFile = fiSource, DestinationFile = fiDestination, FileCopyException = ex });
                }
            }
            else
            {
                //report 
                OnFileCopyNoAction(new FileCopyActionEventArgs() { SourceFile = fiSource, DestinationFile = fiDestination });
            }
        }
        #endregion



        #region methods
        public void ExecuteFileCopyAction(
            string SourceFileName,
            string Destination)
        {
            _executeFileCopyAction(SourceFileName, Destination);
        }
        #endregion
    }
}
